Array.prototype.sortNum = function(index, rev){
    var tmp;
    for(var i=0;i<this.length;i++){
        for(var j=0;j<this.length;j++){
            if(!rev){
                if(+this[i][index] < +this[j][index]){
                    tmp = this[i];
                    this[i] = this[j];
                    this[j] = tmp;
                }
            }else{
                if(+this[i][index] > +this[j][index]){
                    tmp = this[i];
                    this[i] = this[j];
                    this[j] = tmp;
                }
            } 
        }
    }
};
    Array.prototype.sortAlpha = function(index, rev){
        var tmp;
        for(var i=0;i<this.length;i++){
            for(var j=0;j<this.length;j++){
                if(!rev){
                    if(this[i][index].toLowerCase() < this[j][index].toLowerCase()){
                        tmp = this[i];
                        this[i] = this[j];
                        this[j] = tmp;
                    }
                }else{
                    if(this[i][index].toLowerCase() > this[j][index].toLowerCase()){
                        tmp = this[i];
                        this[i] = this[j];
                        this[j] = tmp;
                    }
                }
            }
        }
    };

    //Can probably be optimized
    Array.prototype.sortCleanNum = function(index, rev){
        var tmp;
        for(var i=0;i<this.length;i++){
            for(var j=0;j<this.length;j++){
                var ii = this[i][index] + '';
                var jj = this[j][index] + '';
                if(ii.indexOf('>') >= 0){
                    var a = ii.indexOf('>');
                    var b = ii.lastIndexOf('<');
                    ii = ii.substring(a+1, b);
                }
                if(ii.indexOf('(') >=0 && ii.indexOf(')') >= 0){
                    var a = ii.indexOf('(');
                    var b = ii.indexOf(')');
                    ii = '-' + ii.substring(a+1, b);
                }
            
                if(jj.indexOf('>') >= 0){
                    var c = jj.indexOf('>');
                    var d = jj.lastIndexOf('<');
                    jj = jj.substring(c+1, d);
                }
                if(jj.indexOf('(') >=0 && jj.indexOf(')') >= 0){
                    var c = jj.indexOf('(');
                    var d = jj.indexOf(')');
                    jj = '-' + jj.substring(c+1, d);
                }
                ii = ii.replace(/(:|,|898816)/g,'');
                jj = jj.replace(/(:|,|898816)/g,'');
                ii = +ii;
                jj = +jj;
                if(!rev){
                    if(ii < jj){
                        tmp = this[i];
                        this[i] = this[j];
                        this[j] = tmp;
                    }
                }else{
                    if(ii > jj){
                        tmp = this[i];
                        this[i] = this[j];
                        this[j] = tmp;
                    }
                }
            }
        }
    };

    Array.prototype.sortDateTimeFull = function(index, rev){
        var tmp;
        for(var i=0;i<this.length;i++){
            for(var j=0;j<this.length;j++){
                var ii = this[i][index].split(" ");
                var jj = this[j][index].split(" ");
                var idate = ii[0].split("-");
                var itime = ii[1].replace(/:/g,'');
                ii = '' + idate[2]+idate[0]+idate[1]+itime;
                var jdate = jj[0].split("-");
                var jtime = jj[1].replace(/:/g,'');
                jj = '' + jdate[2]+jdate[0]+jdate[1]+jtime;
                if(!rev){
                    if(+ii < +jj){
                        tmp = this[i];
                        this[i] = this[j];
                        this[j] = tmp;
                    }
                }else{
                    if(+ii > +jj){
                        tmp = this[i];
                        this[i] = this[j];
                        this[j] = tmp;
                    }
                }
            }
        }
    };
    Array.prototype.sortDateTime = function(index, rev){
        var tmp;
        for(var i=0;i<this.length;i++){
            for(var j=0;j<this.length;j++){
                var idate = this[i][index].split("-");
                var jdate = this[j][index].split("-");
                var ii = '' + idate[2]+idate[0]+idate[1];
                var jj = '' + jdate[2]+jdate[0]+jdate[1];
                if(!rev){
                    if(+ii < +jj){
                        tmp = this[i];
                        this[i] = this[j];
                        this[j] = tmp;
                    }
                }else{
                    if(+ii > +jj){
                        tmp = this[i];
                        this[i] = this[j];
                        this[j] = tmp;
                    }
                }
            }
        }
    };

var DataTable = Class.extend({
    props: {
        position: "absolute",
        visibility: "hidden",
        display: "block"
    },
    init: function(target, options){
        this.el = {};
        this.options = {};
        this.cls = [];
        this.columns = [];
        this.allRows = [];
        this.visibleRows = [];
        this.sort = [];
        this.page = 1;
        this.pagelength = 0;
        this.paging = false;
        this.showStatus = true;
        this.startRow = 0;
        this.endRow = 0;
        this.target = target;
        this.filterData = [];
        this.el.table = $('#' + target);
        this.el.table.addClass('tableview_table');
        this.el.header = $('#' + this.target + ' thead');
        this.el.body = $('#' + this.target + ' tbody');
        this.el.wrapper = $('<div id="' + target + '_wrapper" class="tableview_wrapper" />');
        this.el.table.wrap(this.el.wrapper);
        var self = this;
        
        this.buildOptions(options);                 
        this.setup();
    },
    buildOptions: function(options){
        this.options = options;
        if(this.options.paging) this.paging = options.paging;
        if(!this.options.paging && options.pagelength) this.paging = true;
        if(this.options.showStatus != undefined) this.showStatus = options.showStatus;
        this.setupHeaders(options);
        if(options.pagelength) this.pagelength = options.pagelength;
        this.cls = [];
        for(var i=0; i < this.sort.length; i++){
            this.cls[i] = '';
        }
        if(options.cls){
            for(var i = 0; i < this.cls.length; i++){
                if(options.cls['col' + i]){
                    this.cls[i] = options.cls['col' + i];
                }
            }
        }
        if(options.sort){
            for(var i = 0; i < this.sort.length; i++){
                var col = options.sort['col' + i];
                if(col){
                    this.sort[i] = col;
                    //if the column doesn't have a class and it's a number,
                    //float it right
                    if(col == 'num' || col == 'cleannum' && this.cls[i] == ''){
                        this.cls[i] = 'text_right';
                    }
                    if(col == 'datetime' && this.cls[i] == ''){
                        this.cls[i] = 'text_center';
                    }
                    if(col == 'str'){
                        this.cls[i] = 'text_left';
                    }
                }
            }
        }

    },
    setup: function(){
        var self = this;
        this.setupScroll();
        this.tablewrapper = $('<div id="' + this.target + '_tbl_wrapper" class="tableview_overflow_wrapper" />');
        this.tablewrapper.scroll(function(e){
            $('#' + self.target + '_scroll_wrapper').scrollLeft($(this).scrollLeft());
        });
        this.el.table.wrap(this.tablewrapper);
        $('.tableview_page_link', this.el.table).live('click', function(e){
            e.preventDefault();
            self.changePage(parseFloat($(this).attr('data-page')));
        });
        if(this.paging){
            $('#' + this.target + '_paging_first').live('click', function(e){
                e.preventDefault();
                self.changePage(1);
            });
            $('#' + this.target + '_paging_prev').live('click', function(e){
                e.preventDefault();
                self.changePage(--self.page);
            });
            $('#' + this.target + '_paging_next').live('click', function(e){
                e.preventDefault();
                self.changePage(++self.page);
            });
            $('#' + this.target + '_paging_last').live('click', function(e){
                e.preventDefault();
                self.changePage(Math.ceil(self.rows.length / self.pagelength));
            });
        }
        this.setupStatus();
        this.loadDom();
        this.show();
    },
    setupStatus: function(){
        this.statusTop = $('<div id="' + this.target + '_status_top" class="tableview_status_bar"><a name="' + this.target + '_top"></a><div class="tableview_status"></div><div class="tableview_paging"></div></div>');
        this.statusBottom = $('<div id="' + this.target + '_status_bottom" class="tableview_status_bar"><div class="tableview_status"></div><div class="tableview_paging"></div></div>');
        this.statusTop.insertBefore(this.scrollwrapper);
        //this is ugly find out why it's not mapping correctly
        this.statusBottom.insertAfter($('#' + this.target + '_tbl_wrapper'));
    },
    setupScroll: function(){
        this.scrollwrapper = $('<div id="' + this.target + '_scroll_wrapper" class="tableview_overflow_wrapper" />');
        var scrollContent = $('<div id="' + this.target + '_scroll_target" />');
        var dim = this.el.table.getHiddenDimensions(true);
        scrollContent.css({
            'width': dim.w,
            'height': $.browser.mozilla? 18 : 1
        });
        //this.el.table.css('width', this.el.table.width());
        scrollContent.appendTo(this.scrollwrapper);
        this.scrollwrapper.insertBefore(this.el.table);
        var self = this;
        this.scrollwrapper.scroll(function(e){
            $('#' + self.target + '_tbl_wrapper').scrollLeft($(this).scrollLeft());
        });
    },
    setupHeaders: function(options){
        this.columns = this.el.header.children().last();
        this.columns = this.columns.children();
        this.columns.addClass('sorting');
        var self = this;
        this.columns.each(function(i, col){
            var visible = true;
            if(options.hidden){
                for(var j=0; j < options.hidden.length; j++){
                    if(options.hidden[j] == i){
                        visible = false;
                        $(col).remove();
                        break;
                    }
                }
            }
            if(visible){
                self.sort.push(null);
                var dim = $(col).getHiddenDimensions();
                $(col).css('width', dim.w);
                $(col).addClass('tableview_sortable');
                $(col).attr('data-id', i);
            }
        });
        this.el.header.delegate("th.tableview_sortable", "click", function(){
            self.headerClick(this);
        });
    },
    resizeTable: function(){
        var dim =  this.el.table.getHiddenDimensions(true);
        var self = this;
        $('#' + self.target + '_scroll_target').css('width', dim.w);
    },
    filter: function(column, value, filter){
        this.visibleRows = [];
        this.filterData = [];
        this.filterData.push([(column +1), value, filter]);
        this.show();
    },
    clearfilter: function(){
        this.filterData = [];
        this.visibleRows = this.rows;
        this.show();
    },
    loadNewData: function(dataset){
        this.rows = [];
        for(var i=0; i < dataset.length; i++){
            var row = [i]
            row = row.concat(dataset[i]);
            this.rows.push(row);
        }
        this.visibleRows = this.rows;
        this.resizeTable();
        this.show();
        this.resizeTable();
    },
    loadDom: function(){
        this.rows = [];
        var rows = this.el.body.children();
        var self = this;
        rows.each(function(i, tr){
            var row = [i];
            $(tr).children().each(function(j, td){
                row.push($(td).html());

            });
            self.rows.push(row);
        });
        this.visibleRows = this.rows;
    },
    headerClick: function(column){
        //get state of column
        var sort = this.sortDirection(column);
        this.columns.removeClass('sorting_asc').removeClass('sorting_desc');
        switch(sort){
            case null:
                $(column).addClass('sorting_asc');
                break;
            case 'asc':
                $(column).addClass('sorting_desc');
                break;
        }
        if(this.rows.length > 0){
            this.sortTable(column);
        }

    },
    sortDirection: function(column){
        var sort = null;
        if($(column).hasClass('sorting_asc')) sort = 'asc';
        if($(column).hasClass('sorting_desc')) sort = 'desc';
        return sort;

    },
    sortTable: function(column){
        this.page = 1;
        var pos = parseInt($(column).attr('data-id'));
        var loc = pos + 1;
        var sortType = this.sort[pos];
        var direction = this.sortDirection(column);
        var dir = (direction == 'asc')? false: true;
        //console.log(this.sort);
        //console.log(loc + ' ' + sortType);
        if(direction == null){
            this.visibleRows.sortNum(0);
        }else{

            switch(sortType){
                case 'alpha':
                    this.visibleRows.sortAlpha(loc, dir);
                    break;
                case null:
                    this.sortDiscover(loc, dir);
                    break;
                case 'num':
                    this.visibleRows.sortNum(loc, dir);
                    break;
                case 'datetime':
                    this.visibleRows.sortDateTime(loc, dir);
                    break;
                case 'datetimefull':
                    this.visibleRows.sortDateTimeFull(loc, dir);
                    break;
                case 'cleannum':
                    this.visibleRows.sortCleanNum(loc, dir);
                    break;
            }
        }
        this.show();

    },
    // quick check to see if it's a number or make it alpha
    sortDiscover: function(loc, dir){
        var col1 = parseFloat(this.rows[0][loc]);
        var col2 = parseFloat(this.rows[0][loc]);
        if(col1 && col2){
            this.sort[loc-1] = 'cleannum';
            this.rows.sortCleanNum(loc, dir);
        }else{
            this.sort[loc-1] = 'alpha';
            this.rows.sortAlpha(loc, dir);
        }

    },
    filteredRows: function(){
        if(this.filterData.length > 0){
            this.visibleRows = [];
            var allRows = [];
            for(var i=0; i < this.rows.length; i++){
                allRows.push(this.rows[i]);
            }
            for(var i=0; i < this.filterData.length; i++){
                var col = this.filterData[i][0];
                var val = this.filterData[i][1];
                var func = this.filterData[i][2];
                for(var j=0; j < allRows.length; j++){
                    if(func){
                        if(func(allRows[j][col])){
                            this.visibleRows.push(allRows[j]);
                        }
                    }else{
                        if(allRows[j][col] == val){
                            this.visibleRows.push(allRows[j]);
                        }
                    }
                }
            }
            return this.visibleRows;
        }else{
            return this.rows;
        }
    },
    show: function(){
        //console.log(this.sort);
        this.el.body.empty();
        this.startRow = 0;
        this.endRow = 0;
        var rows = this.filteredRows();
        var len = rows.length;//this.rows.length;
        if(len == 0){
            this.paging = false;
            this.showEmpty();

        }else{
            var even = false;
            if(this.pagelength > len || this.pagelength == 0){
                this.startRow = 0;
                this.endRow = len;
                this.paging = false;
                for(var i=0; i < len; i++){
                    var row = rows[i];
                    var html = '<tr ';
                    if(even) html += 'class="even"';
                    html += '>';
                    var visible = true;
                    for(var j=1; j < row.length; j++){
                        visible = true;
                        if(this.options.hidden){
                            for(var h=0; h < this.options.hidden.length; h++){
                                if(j == (this.options.hidden[h] + 1)){
                                    visible = false;
                                    break;
                                }
                            }
                        }
                        if(visible){
                            html += '<td';
                            if(this.cls[j-1] != ''){
                                html += ' class="' + this.cls[j-1] + '"';
                            }
                            html += '>' + row[j] + '</td>';
                        }
                    }

                    html += '</tr>';
                    $(html).appendTo(this.el.body);
                    even = !even;
                }
            }else{
                this.paging = true;
                this.startRow = (this.page-1) * this.pagelength;
                this.endRow = this.startRow + this.pagelength;
                //var visibleLength = (this.options.hidden)? (this.columns.length - this.options.hidden.length) : this.columns.length;
                for(var i=this.startRow; i < this.endRow; i++){
                    var row = rows[i];
                    var html = '<tr ';
                    if(even) html += 'class="even"';
                    html += '>';
                    if(row){
                        var visible = true;
                        for(var j=1; j < row.length; j++){
                            visible = true;
                            if(this.options.hidden){                                
                                for(var h=0; h < this.options.hidden.length; h++){
                                    if(j == (this.options.hidden[h] + 1)){
                                        visible = false;
                                        break;
                                    }
                                }
                            }
                            if(visible){
                                html += '<td';
                                if(this.cls[j-1] != ''){
                                    html += ' class="' + this.cls[j-1] + '"';
                                }
                                html += '>' + row[j] + '</td>';
                            }                                
                        }
                    }else{
                        for(var j=0; j < this.columns.length; j++){
                            html += '<td>&nbsp;</td>';
                        }
                    }
                    html += '</tr>';
                    $(html).appendTo(this.el.body);

                    even = !even;
                }//);
            }
        }
        this.updateStatus();
        this.updatePaging();
    },
    updateStatus: function(){
        if(this.showStatus){
            if(this.rows.length > 0){
                var start = (this.startRow == 0)? 1: this.startRow;
                var end = (this.endRow > this.filteredRows().length)? this.filteredRows().length: this.endRow;
                var filter = '';
                if(this.filterData.length > 0){
                    filter = '(filtered from total: ' + this.rows.length + ')';
                }
                $('.tableview_status', $('#' + this.target + '_wrapper')).html('Showing: ' + start + '-' + end + ' of ' + this.visibleRows.length + ' ' + filter);
            }else{
                $('.tableview_status', $('#' + this.target + '_wrapper')).html('This table is empty.');
            }
        }

    },
    updatePaging: function(){
        if(this.paging){
            var html = '';
            var max = Math.ceil(this.rows.length / this.pagelength);
            var self = this;
            if(this.page != 1){
                html += '<a id="' + this.target + '_paging_first" class="tableview_first" href="#' + this.target + '_top">first</a><a id="' + this.target + '_paging_prev" class="tableview_prev" href="#' + this.target + '_top">previous</a>';
            }else{
                html += '<span class="tableview_first">first</span><span class="tableview_prev">previous</span>';
            }
            for(var i=1; i <= max; i++){
                var cls = (i == this.page)? ' tableview_current_page' : '';
                var a = '<a id="' + this.target + '_paging_' + i + '" class="tableview_page_link' + cls + '" href="#' + this.target + '_top" data-page="' + i + '">' + i + '</a>';
                html += a;
            }
            if(this.page != max){
                html += '<a id="' + this.target + '_paging_next" class="tableview_next" href="#' + this.target + '_top">next</a><a id="' + this.target + '_paging_last" class="tableview_last" href="#' + this.target + '_top">last</a>';
            }else{
                html += '<span class="tableview_next">next</span><span class="tableview_last">last</span>';
            }
            $('.tableview_paging', $('#' + this.target + '_wrapper')).html(html);
        }else{
            $('.tableview_paging', $('#' + this.target + '_wrapper')).html('');
        }
    },
    changePage: function(page){
        this.page = page;
        this.show();
    },
    showEmpty: function(){
        this.el.body.empty();
        var row = $('<tr><td colspan="' + this.columns.length + '">No Records Found.</td></tr>');
        row.appendTo(this.el.body);
    },
    reset: function(){

    }
});
